"""
路由管理服务层
提供路由的业务逻辑处理
"""

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, func, delete
from sqlalchemy.orm import selectinload
from fastapi import HTTPException, status
from typing import List, Optional
import logging
from datetime import datetime

from app.models.auth import Route, Permission, RoutePermission, User, Role, RolePermission, UserRole
from app.schemas.route import (
    RouteResponse, RouteListResponse, RouteCreate, RouteUpdate,
    RoutePermissionResponse, MenuRouteResponse, PermissionInfo
)
from app.utils.timezone_utils import get_shanghai_now

logger = logging.getLogger(__name__)


class RouteService:
    """路由管理服务"""

    async def get_routes(
        self,
        db: AsyncSession,
        parent_id: Optional[int] = None,
        is_menu: Optional[bool] = None,
        is_active: Optional[bool] = True,
        search: Optional[str] = None
    ) -> RouteListResponse:
        """获取路由列表"""
        try:
            # 构建查询条件
            conditions = []
            
            if parent_id is not None:
                conditions.append(Route.parent_id == parent_id)
            else:
                conditions.append(Route.parent_id.is_(None))
            
            if is_menu is not None:
                conditions.append(Route.is_menu == is_menu)
            
            if is_active is not None:
                conditions.append(Route.is_active == is_active)
            
            if search:
                search_pattern = f"%{search}%"
                conditions.append(
                    or_(
                        Route.name.ilike(search_pattern),
                        Route.display_name.ilike(search_pattern),
                        Route.description.ilike(search_pattern),
                        Route.path.ilike(search_pattern)
                    )
                )
            
            # 查询路由
            stmt = (
                select(Route)
                .where(and_(*conditions))
                .options(
                    selectinload(Route.route_permissions).selectinload(RoutePermission.permission),
                    selectinload(Route.children)
                )
                .order_by(Route.sort_order, Route.id)
            )
            
            result = await db.execute(stmt)
            routes = result.scalars().all()
            
            # 统计总数
            count_stmt = select(func.count(Route.id)).where(and_(*conditions))
            count_result = await db.execute(count_stmt)
            total = count_result.scalar()
            
            # 转换为响应模式
            route_responses = [RouteResponse.from_orm(route) for route in routes]
            
            return RouteListResponse(routes=route_responses, total=total)
            
        except Exception as e:
            logger.error(f"获取路由列表异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取路由列表失败"
            )

    async def get_route_tree(
        self,
        db: AsyncSession,
        is_active: Optional[bool] = True
    ) -> List[RouteResponse]:
        """获取路由树形结构"""
        try:
            # 构建查询条件
            conditions = [Route.parent_id.is_(None)]  # 只获取顶级路由

            if is_active is not None:
                conditions.append(Route.is_active == is_active)

            # 查询顶级路由及其所有子路由，使用更深层的预加载
            stmt = (
                select(Route)
                .where(and_(*conditions))
                .options(
                    selectinload(Route.route_permissions).selectinload(RoutePermission.permission),
                    # 预加载多层子路由关系，避免懒加载
                    selectinload(Route.children).selectinload(Route.route_permissions).selectinload(RoutePermission.permission),
                    selectinload(Route.children).selectinload(Route.children).selectinload(Route.route_permissions).selectinload(RoutePermission.permission)
                )
                .order_by(Route.sort_order, Route.id)
            )

            result = await db.execute(stmt)
            routes = result.scalars().all()

            # 为了避免greenlet问题，我们需要在异步上下文中完成所有数据访问
            # 先将所有路由数据转换为字典格式，避免后续访问ORM对象
            def route_to_dict(route):
                """将Route对象转换为字典，避免后续懒加载"""
                return {
                    'id': route.id,
                    'path': route.path,
                    'name': route.name,
                    'display_name': route.display_name,
                    'description': route.description,
                    'icon': route.icon,
                    'component': route.component,
                    'parent_id': route.parent_id,
                    'sort_order': route.sort_order,
                    'is_menu': route.is_menu,
                    'is_active': route.is_active,
                    'is_system': route.is_system,
                    'meta': route.meta,
                    'created_at': route.created_at,
                    'updated_at': route.updated_at,
                    'children': [route_to_dict(child) for child in route.children] if route.children else [],
                    'permissions': [
                        {
                            'id': rp.permission.id,
                            'name': rp.permission.name,
                            'display_name': rp.permission.display_name,
                            'description': rp.permission.description,
                            'resource': rp.permission.resource,
                            'action': rp.permission.action
                        }
                        for rp in route.route_permissions if rp.is_active and rp.permission
                    ] if route.route_permissions else []
                }

            # 在异步上下文中转换所有数据
            route_dicts = [route_to_dict(route) for route in routes]

            # 递归构建树形结构（现在使用字典数据，不会触发懒加载）
            def build_tree(route_dict):
                # 创建RouteResponse对象
                # 提取权限名称
                permission_names = [perm['name'] for perm in route_dict['permissions']] if route_dict['permissions'] else None

                route_data = RouteResponse(
                    id=route_dict['id'],
                    path=route_dict['path'],
                    name=route_dict['name'],
                    display_name=route_dict['display_name'],
                    description=route_dict['description'],
                    icon=route_dict['icon'],
                    component=route_dict['component'],
                    parent_id=route_dict['parent_id'],
                    sort_order=route_dict['sort_order'],
                    is_menu=route_dict['is_menu'],
                    is_active=route_dict['is_active'],
                    is_system=route_dict['is_system'],
                    meta=route_dict['meta'],
                    created_at=route_dict['created_at'],
                    updated_at=route_dict['updated_at'],
                    permissions=[
                        PermissionInfo(**perm) for perm in route_dict['permissions']
                    ] if route_dict['permissions'] else None,
                    permission_names=permission_names
                )

                if route_dict['children']:
                    # 过滤并排序子路由
                    active_children = [
                        child for child in route_dict['children']
                        if not is_active or child['is_active']
                    ]
                    active_children.sort(key=lambda x: (x['sort_order'], x['id']))
                    route_data.children = [build_tree(child) for child in active_children]

                return route_data

            return [build_tree(route_dict) for route_dict in route_dicts]

        except Exception as e:
            logger.error(f"获取路由树异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取路由树失败"
            )

    async def get_user_menu_routes(
        self,
        db: AsyncSession,
        user: User
    ) -> List[RouteResponse]:
        """获取用户可访问的菜单路由"""
        try:
            # 查询所有菜单路由及其权限信息
            stmt = (
                select(Route)
                .where(Route.is_menu == True)
                .where(Route.is_active == True)
                .options(
                    selectinload(Route.children).selectinload(Route.route_permissions).selectinload(RoutePermission.permission),
                    selectinload(Route.route_permissions).selectinload(RoutePermission.permission)
                )
                .order_by(Route.sort_order)
            )

            result = await db.execute(stmt)
            routes = result.scalars().all()

            # 构建路由树结构
            route_map = {}
            root_routes = []

            # 先创建所有路由的RouteResponse对象
            for route in routes:
                # 提取权限名称
                permission_names = []
                for rp in route.route_permissions:
                    if rp.is_active and rp.permission:
                        permission_names.append(rp.permission.name)

                route_response = RouteResponse(
                    id=route.id,
                    path=route.path,
                    name=route.name,
                    display_name=route.display_name,
                    description=route.description,
                    icon=route.icon,
                    component=route.component,
                    parent_id=route.parent_id,
                    sort_order=route.sort_order,
                    is_menu=route.is_menu,
                    is_active=route.is_active,
                    is_system=route.is_system,
                    meta=route.meta or {},
                    created_at=route.created_at,
                    updated_at=route.updated_at,
                    children=[],
                    permissions=None,  # 简化，不返回完整权限对象
                    permission_names=permission_names if permission_names else None
                )

                route_map[route.id] = route_response

                if route.parent_id is None:
                    root_routes.append(route_response)

            # 构建父子关系
            for route in routes:
                if route.parent_id and route.parent_id in route_map:
                    parent = route_map[route.parent_id]
                    child = route_map[route.id]
                    parent.children.append(child)

            return root_routes



        except Exception as e:
            logger.error(f"获取用户菜单路由异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取用户菜单路由失败"
            )

    async def get_route(self, db: AsyncSession, route_id: int) -> RouteResponse:
        """获取路由详情"""
        try:
            stmt = (
                select(Route)
                .where(Route.id == route_id)
                .options(
                    selectinload(Route.route_permissions).selectinload(RoutePermission.permission),
                    selectinload(Route.children),
                    selectinload(Route.parent)
                )
            )
            
            result = await db.execute(stmt)
            route = result.scalar_one_or_none()
            
            if not route:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="路由不存在"
                )
            
            return RouteResponse.from_orm(route)
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"获取路由详情异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取路由详情失败"
            )

    async def create_route(
        self,
        db: AsyncSession,
        route_data: RouteCreate,
        current_user: User
    ) -> RouteResponse:
        """创建路由"""
        try:
            # 检查路径是否已存在
            stmt = select(Route).where(Route.path == route_data.path)
            result = await db.execute(stmt)
            if result.scalar_one_or_none():
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="路由路径已存在"
                )
            
            # 检查父路由是否存在
            if route_data.parent_id:
                stmt = select(Route).where(Route.id == route_data.parent_id)
                result = await db.execute(stmt)
                parent_route = result.scalar_one_or_none()
                if not parent_route:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="父路由不存在"
                    )
            
            # 创建路由
            route = Route(
                path=route_data.path,
                name=route_data.name,
                display_name=route_data.display_name,
                description=route_data.description,
                icon=route_data.icon,
                component=route_data.component,
                parent_id=route_data.parent_id,
                sort_order=route_data.sort_order,
                is_menu=route_data.is_menu,
                is_active=route_data.is_active,
                is_system=False,  # 用户创建的路由都是非系统路由
                meta=route_data.meta
            )
            
            db.add(route)
            await db.commit()
            await db.refresh(route)
            
            logger.info(f"路由创建成功：{route.path} (by {current_user.username})")
            return RouteResponse.from_orm(route)
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"创建路由异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建路由失败"
            )

    async def update_route(
        self,
        db: AsyncSession,
        route_id: int,
        route_data: RouteUpdate,
        current_user: User
    ) -> RouteResponse:
        """更新路由"""
        try:
            stmt = select(Route).where(Route.id == route_id)
            result = await db.execute(stmt)
            route = result.scalar_one_or_none()

            if not route:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="路由不存在"
                )

            # 系统路由的某些字段不允许修改
            if route.is_system:
                restricted_fields = {'path', 'name'}
                update_data = route_data.dict(exclude_unset=True)
                for field in update_data:
                    if field in restricted_fields:
                        raise HTTPException(
                            status_code=status.HTTP_400_BAD_REQUEST,
                            detail=f"系统路由不允许修改字段: {field}"
                        )

            # 检查父路由循环引用
            if route_data.parent_id is not None and route_data.parent_id != route.parent_id:
                if route_data.parent_id == route.id:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="路由不能设置自己为父路由"
                    )

                # 检查是否会形成循环
                if await self._would_create_cycle(db, route.id, route_data.parent_id):
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="设置父路由会形成循环引用"
                    )

            # 更新路由信息
            update_data = route_data.dict(exclude_unset=True)
            for field, value in update_data.items():
                setattr(route, field, value)

            route.updated_at = get_shanghai_now()
            await db.commit()

            logger.info(f"路由更新成功：{route.path} (by {current_user.username})")
            return RouteResponse.from_orm(route)

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"更新路由异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="更新路由失败"
            )

    async def delete_route(
        self,
        db: AsyncSession,
        route_id: int,
        current_user: User
    ):
        """删除路由"""
        try:
            stmt = select(Route).where(Route.id == route_id)
            result = await db.execute(stmt)
            route = result.scalar_one_or_none()

            if not route:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="路由不存在"
                )

            # 系统路由不允许删除
            if route.is_system:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="系统路由不允许删除"
                )

            # 检查是否有子路由
            stmt = select(func.count(Route.id)).where(Route.parent_id == route_id)
            result = await db.execute(stmt)
            child_count = result.scalar()

            if child_count > 0:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="存在子路由，无法删除"
                )

            route_path = route.path
            await db.delete(route)
            await db.commit()

            logger.info(f"路由删除成功：{route_path} (by {current_user.username})")

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"删除路由异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="删除路由失败"
            )

    async def get_route_permissions(
        self,
        db: AsyncSession,
        route_id: int
    ) -> List[RoutePermissionResponse]:
        """获取路由权限关联"""
        try:
            stmt = (
                select(RoutePermission)
                .where(RoutePermission.route_id == route_id)
                .options(selectinload(RoutePermission.permission))
                .order_by(RoutePermission.id)
            )

            result = await db.execute(stmt)
            route_permissions = result.scalars().all()

            return [RoutePermissionResponse.from_orm(rp) for rp in route_permissions]

        except Exception as e:
            logger.error(f"获取路由权限异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取路由权限失败"
            )

    async def assign_route_permissions(
        self,
        db: AsyncSession,
        route_id: int,
        permission_ids: List[int],
        current_user: User
    ):
        """分配权限给路由"""
        try:
            # 验证路由是否存在
            stmt = select(Route).where(Route.id == route_id)
            result = await db.execute(stmt)
            route = result.scalar_one_or_none()

            if not route:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="路由不存在"
                )

            # 验证权限是否存在
            stmt = select(Permission).where(Permission.id.in_(permission_ids))
            result = await db.execute(stmt)
            permissions = result.scalars().all()

            if len(permissions) != len(permission_ids):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="部分权限不存在"
                )

            # 删除现有的权限关联
            stmt = delete(RoutePermission).where(RoutePermission.route_id == route_id)
            await db.execute(stmt)

            # 创建新的权限关联
            for permission_id in permission_ids:
                route_permission = RoutePermission(
                    route_id=route_id,
                    permission_id=permission_id,
                    is_required=True,
                    is_active=True,
                    created_by=current_user.id
                )
                db.add(route_permission)

            await db.commit()

            logger.info(f"路由权限分配成功：{route.path} -> {permission_ids} (by {current_user.username})")

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"路由权限分配异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="路由权限分配失败"
            )

    async def remove_route_permission(
        self,
        db: AsyncSession,
        route_id: int,
        permission_id: int,
        current_user: User
    ):
        """移除路由权限关联"""
        try:
            stmt = select(RoutePermission).where(
                and_(
                    RoutePermission.route_id == route_id,
                    RoutePermission.permission_id == permission_id
                )
            )
            result = await db.execute(stmt)
            route_permission = result.scalar_one_or_none()

            if not route_permission:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="路由权限关联不存在"
                )

            await db.delete(route_permission)
            await db.commit()

            logger.info(f"路由权限移除成功：route_id={route_id}, permission_id={permission_id} (by {current_user.username})")

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"移除路由权限异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="移除路由权限失败"
            )

    async def _would_create_cycle(
        self,
        db: AsyncSession,
        route_id: int,
        parent_id: int
    ) -> bool:
        """检查设置父路由是否会形成循环引用"""
        try:
            current_parent_id = parent_id
            visited = set()

            while current_parent_id is not None:
                if current_parent_id in visited:
                    return True  # 检测到循环

                if current_parent_id == route_id:
                    return True  # 会形成循环

                visited.add(current_parent_id)

                # 获取当前父路由的父路由
                stmt = select(Route.parent_id).where(Route.id == current_parent_id)
                result = await db.execute(stmt)
                current_parent_id = result.scalar_one_or_none()

            return False

        except Exception as e:
            logger.error(f"检查循环引用异常：{str(e)}")
            return True  # 出错时保守处理，认为会形成循环




    async def batch_update_sort(
        self,
        db: AsyncSession,
        sort_data: List[dict],
        current_user: User
    ) -> List[RouteResponse]:
        """批量更新路由排序"""
        try:
            updated_routes = []

            for item in sort_data:
                route_id = item.get('id')
                sort_order = item.get('sort_order')
                parent_id = item.get('parent_id')

                if not route_id or sort_order is None:
                    continue

                # 获取路由
                stmt = select(Route).where(Route.id == route_id)
                result = await db.execute(stmt)
                route = result.scalar_one_or_none()

                if not route:
                    continue

                # 更新排序和父级关系
                route.sort_order = sort_order
                if parent_id is not None:
                    route.parent_id = parent_id if parent_id != 0 else None

                updated_routes.append(route)

            await db.commit()

            # 返回更新后的路由列表
            result_routes = []
            for route in updated_routes:
                await db.refresh(route)
                result_routes.append(RouteResponse.from_orm(route))

            logger.info(f"批量更新路由排序成功：更新{len(updated_routes)}个路由")
            return result_routes

        except Exception as e:
            logger.error(f"批量更新路由排序异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="批量更新排序失败"
            )

    async def get_route_statistics(self, db: AsyncSession) -> dict:
        """获取路由访问统计"""
        try:
            # 统计路由总数
            total_stmt = select(func.count(Route.id))
            total_result = await db.execute(total_stmt)
            total_routes = total_result.scalar()

            # 统计活跃路由数
            active_stmt = select(func.count(Route.id)).where(Route.is_active == True)
            active_result = await db.execute(active_stmt)
            active_routes = active_result.scalar()

            # 统计菜单路由数
            menu_stmt = select(func.count(Route.id)).where(
                and_(Route.is_menu == True, Route.is_active == True)
            )
            menu_result = await db.execute(menu_stmt)
            menu_routes = menu_result.scalar()

            # 统计系统路由数
            system_stmt = select(func.count(Route.id)).where(Route.is_system == True)
            system_result = await db.execute(system_stmt)
            system_routes = system_result.scalar()

            # 统计权限关联数
            permission_stmt = select(func.count(RoutePermission.id)).where(
                RoutePermission.is_active == True
            )
            permission_result = await db.execute(permission_stmt)
            permission_associations = permission_result.scalar()

            # 按层级统计路由分布
            level_stats = {}
            routes_stmt = select(Route).where(Route.is_active == True)
            routes_result = await db.execute(routes_stmt)
            routes = routes_result.scalars().all()

            for route in routes:
                level = await self._get_route_level(db, route)
                level_stats[f"level_{level}"] = level_stats.get(f"level_{level}", 0) + 1

            return {
                "total_routes": total_routes,
                "active_routes": active_routes,
                "inactive_routes": total_routes - active_routes,
                "menu_routes": menu_routes,
                "system_routes": system_routes,
                "custom_routes": total_routes - system_routes,
                "permission_associations": permission_associations,
                "level_distribution": level_stats,
                "statistics_time": get_shanghai_now().isoformat()
            }

        except Exception as e:
            logger.error(f"获取路由统计异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取统计失败"
            )

    async def _get_route_level(self, db: AsyncSession, route: Route) -> int:
        """获取路由层级"""
        level = 0
        current_parent_id = route.parent_id

        while current_parent_id:
            level += 1
            stmt = select(Route.parent_id).where(Route.id == current_parent_id)
            result = await db.execute(stmt)
            current_parent_id = result.scalar_one_or_none()

            # 防止无限循环
            if level > 10:
                break

        return level
